package tictactoe.screens;

import java.awt.*;
import java.awt.Font.*;
import java.awt.event.*;
import java.io.*;
import java.util.regex.*;
import javax.swing.*;

import tictactoe.*;
import tictactoe.types.*;

/**
 *
 * @author Ryan Falls
 */
public class OptionsMenuScreen extends MenuScreen
{
    //Components
    protected JLabel title;
    //protected JLabel fullScreenButton;
    protected JLabel styleLabel;
    protected JComboBox stylesList;
    protected JLabel colorLabel;
    protected JLabel colorLabelX;
    protected JLabel colorLabelO;
    protected JLabel previewIconsLabel;
    protected JLabel iconLabelX;
    protected JLabel iconLabelO;
    protected JLabel backButton;

    //TODO Main Menu Screen
    public OptionsMenuScreen(TicTacToe ttt)
    {
	this.ttt = ttt;
	setLayout(new GridBagLayout());

	GridBagConstraints constraints = new GridBagConstraints();
	ImageIcon image;

	//Add Title
	title = new JLabel("Options");
	title.setFont(ttt.menuTitleFont);
	constraints.gridx = 0;
	constraints.gridy = 0;
	constraints.gridheight = 1;
	constraints.gridwidth = 3;
	constraints.insets = new Insets(10, 10, 5, 10);
	add(title, constraints);

	//Configure Menu Item Properties
	constraints.gridwidth = 2;
	constraints.anchor = GridBagConstraints.WEST;
	constraints.insets.top = 5;

	//Add Full Screen Button
	/*
	fullScreenButton = new JLabel("Full Screen");
	//fullScreenButton.setBorder(BorderFactory.createEmptyBorder());
	fullScreenButton.setFont(ttt.menuItemFont);
	constraints.gridy = 2;
	add(fullScreenButton,constraints);
	 */

	//Add Style Label
	styleLabel = new JLabel("Select Style");
	styleLabel.setFont(ttt.menuItemFont);
	constraints.gridy = 3;
	add(styleLabel, constraints);

	//Add Styles List
	stylesList = new JComboBox();
	stylesList.setEditable(false);
	constraints.gridx = 2;
	constraints.gridwidth = 2;
	ReloadStyles();
	stylesList.addItemListener(new ItemListener()
	{
	    public void itemStateChanged(ItemEvent e)
	    {
		if(e.getStateChange() == ItemEvent.SELECTED)
		{
		    String s = (String) (e.getItem());
		    //OptionsMenuScreen.this.ttt.currentStyle = null;
		    for(Style t : OptionsMenuScreen.this.ttt.styles)
		    {
			if(t.name.equals(s))
			{
			    OptionsMenuScreen.this.ttt.currentStyle = t;
			    OptionsMenuScreen.this.iconLabelX.setIcon(t.X);
			    OptionsMenuScreen.this.iconLabelO.setIcon(t.O);
			}
		    }
		    if(OptionsMenuScreen.this.ttt.styles == null)
		    {
			//TODO: Throw Error
		    }
		}
	    }
	});
	add(stylesList, constraints);

	//Add color label
	colorLabel = new JLabel("Player Colors:");
	colorLabel.setFont(ttt.menuItemFont);
	constraints.gridx = 0;
	constraints.gridy = 4;
	constraints.gridwidth = 2;
	add(colorLabel, constraints);

	//Add Player X color label
	colorLabelX = new JLabel("Player X");
	colorLabelX.setBorder(ttt.emptyBorder);
	colorLabelX.setFont(ttt.menuItemFont);
	colorLabelX.setOpaque(true);
	colorLabelX.setBackground(Color.blue);
	colorLabelX.addMouseListener(new MenuItemMouseAdapter()
	{
	    @Override public void mouseClicked(MouseEvent e)
	    {
		Component c = e.getComponent();
		Color col = JColorChooser.showDialog(c, "Choose color for Player X", c.getBackground());
		if(col != null)
		{
		    OptionsMenuScreen.this.iconLabelX.setBackground(col);
		    c.setBackground(col);
		}
	    }
	});
	constraints.gridx = 2;
	constraints.gridy = 4;
	constraints.gridwidth = 1;
	add(colorLabelX, constraints);

	//Add Player O color label
	colorLabelO = new JLabel("Player O");
	colorLabelO.setBorder(ttt.emptyBorder);
	colorLabelO.setFont(ttt.menuItemFont);
	colorLabelO.setOpaque(true);
	colorLabelO.setBackground(Color.red);
	colorLabelO.addMouseListener(new MenuItemMouseAdapter()
	{
	    @Override public void mouseClicked(MouseEvent e)
	    {
		Component c = e.getComponent();
		Color col = JColorChooser.showDialog(c, "Choose color for Player O", c.getBackground());
		if(col != null)
		{
		    OptionsMenuScreen.this.iconLabelO.setBackground(col);
		    c.setBackground(col);
		}
	    }
	});
	constraints.gridx = 3;
	constraints.gridy = 4;
	constraints.gridwidth = 1;
	add(colorLabelO, constraints);

	//Add preview label for icons
	previewIconsLabel = new JLabel("Preview Style:");
	previewIconsLabel.setFont(ttt.menuItemFont);
	constraints.gridx = 0;
	constraints.gridy = 5;
	add(previewIconsLabel, constraints);

	//Add label that shows Player X icon
	iconLabelX = new JLabel(ttt.currentStyle.X);
	iconLabelX.setOpaque(true);
	iconLabelX.setBackground(Color.blue);//colorLabelX.getBackground());
	constraints.gridx = 2;
	constraints.gridy = 5;
	add(iconLabelX, constraints);

	//Add label that shows Player O icon
	iconLabelO = new JLabel(ttt.currentStyle.O);
	iconLabelO.setOpaque(true);
	iconLabelO.setBackground(Color.red);//colorLabelO.getBackground());
	constraints.gridx = 3;
	constraints.gridy = 5;
	add(iconLabelO, constraints);

	//Add Exit Button
	backButton = new JLabel("Back");
	backButton.setFont(ttt.menuItemFont);
	constraints.gridx = 0;
	constraints.gridy = 6;
	constraints.insets.bottom = 10;
	backButton.addMouseListener(new MenuItemMouseAdapter()
	{
	    @Override public void mouseClicked(MouseEvent e)
	    {
		Component c = e.getComponent();
		OptionsMenuScreen o = (OptionsMenuScreen) (c.getParent());
		o.ChangeScreen(Screens.mainMenu);
	    }
	});
	add(backButton, constraints);
    }

    /**
     * Used to obtain the current Color for Player X.
     * @return A Color object indicating Player X's background color.
     */
    public Color GetPlayerXColor()
    {
	return colorLabelX.getBackground();
    }

    /**
     * Used to obtain the current Color for Player O.
     * @return A Color object indicating Player O's background color.
     */
    public Color GetPlayerOColor()
    {
	return colorLabelO.getBackground();
    }

    /**
     * Parses the styles directory in the games current directory, searching for
     * sets of images that make up styles.
     */
    public void ReloadStyles()
    {
	File currentDir = new File((new File("")).getAbsolutePath() + File.separator + "styles");
	File[] files = currentDir.listFiles();
	java.util.ArrayList<Style> styles = new java.util.ArrayList<Style>();
	Style temp = null;
	if(files != null)
	{
	    for(File f : files)
	    {
		if(f.isDirectory())
		{
		    try
		    {
			temp = ValidateStyle(f);
			if(temp != null)
			{
			    switch(temp.styleType)
			    {
				case XO:
				    styles.add(temp);
				    stylesList.addItem(temp.name);
				    break;
				case XOS:
				    styles.add(temp);
				    stylesList.addItem(temp.name);
				    break;
				case XOD:
				    styles.add(temp);
				    stylesList.addItem(temp.name);
				    break;
				case NONE:
				    break;
				default:
				    //TODO Throw Error
				    break;
			    }
			}
		    }
		    catch (IOException e)
		    {
			//TODO: Throw or log
		    }

		}
	    }
	}
	ttt.styles = new Style[styles.size()];
	styles.toArray(ttt.styles);
	if(ttt.styles.length > 0)
	{
	    ttt.currentStyle = ttt.styles[0];
	}
    }

    /**
     * Tests the given File to determine whether it is a valid style.
     *
     * A valid style is a directory (f.isDirectory()) containing:
     * -3 Images named X, O, and either empty or none
     * and optionally either
     * -a set of images named wincol, winrow, windiag1, and windiag2
     * --Note: win images are the same for both players
     * or
     * -a set of images named wincolO, windiag1X, winrowX, winrowO, wincolX, windiag2X, windiage1O, and windiag2O
     * --Note: win images are different for the two players
     * @param f	The File
     * @return A StyleTypes value indicating what type of style (if any) it is.
     * @see tictactoe.TTTHelpers#StyleTypes
     */
    public static Style ValidateStyle(File f) throws IOException
    {
	//The return value
	Style style = new Style(f.getName(), f, StyleTypes.NONE);
	//Strings for vaious patterns segments
	String sCol = "^wincol";
	String sRow = "^winrow";
	String sDiag1 = "^windiag1";
	String sDiag2 = "^windiag2";
	String SDext = ""; // extension used for single/double x/y (i.e. if single, "", if double, "x" or "y" (see below))
	String ext = "[.](gif|jpg|jpeg|png)$"; //Valid image extensions
	//Patterns for the different files in the style
	Pattern pX = Pattern.compile("^[x]" + ext, Pattern.CASE_INSENSITIVE); // X image
	Pattern pO = Pattern.compile("^[o]" + ext, Pattern.CASE_INSENSITIVE); // O image
	Pattern pE = Pattern.compile("^(empty|none)" + ext, Pattern.CASE_INSENSITIVE); // Empty Image for none/empty spaces
	Pattern pSoND = Pattern.compile("^win(row|col)[ox]" + ext, Pattern.CASE_INSENSITIVE); // Single/NotDual
	Pattern pCol;// = Pattern.compile("^wincol[.](gif|jpg|jpeg|png)");
	Pattern pRow;// = Pattern.compile("^winrow[.](gif|jpg|jpeg|png)");
	Pattern pDiag1;// = Pattern.compile("^windiag1[.](gif|jpg|jpeg|png)");
	Pattern pDiag2;// = Pattern.compile("^windiag2[.](gif|jpg|jpeg|png)");
	//Variables
	String[] files = f.list();
	boolean X = false, O = false, E = false, // Used for recording X, O, and empty/none exists
		col = false, row = false, diag1 = false, diag2 = false, // Used for recording column, row, and diagonals exist
		SoND = false; // Used for indicating Single (true) / Not Double
	int i;// Iterators


	for(i = 0; i < files.length; i++)
	{
	    files[i] = files[i].toLowerCase();

	    // General format:
	    // Exists = (IF Exists ? Return exists : ELSE check if it exists)
	    if(pX.matcher(files[i]).matches())
	    {
		X = true;
		style.X = new ImageIcon(f.getCanonicalPath() + File.separator + files[i]);
	    }
	    //X = (X ? X : pX.matcher(files[i]).matches());
	    if(pO.matcher(files[i]).matches())
	    {
		O = true;
		style.O = new ImageIcon(f.getCanonicalPath() + File.separator + files[i]);
	    }
	    if(pE.matcher(files[i]).matches())
	    {
		E = true;
		style.none = new ImageIcon(f.getCanonicalPath() + File.separator + files[i]);
	    }
	    //O = (O ? O : pO.matcher(files[i]).matches());
	    SoND = (SoND ? SoND : pSoND.matcher(files[i]).matches());
	}

	//Check to see if it found both X & O
	if(X && O && E)
	{
	    style.styleType = StyleTypes.XO; // If X&O found, style is at least XO

	    if(files.length > 2) // If there are more than 2 files, look for other files
	    {

		if(!SoND) // If Dual, setup to check for x images first
		{
		    SDext = "x";
		}

		// Compile patterns for checking images
		pCol = Pattern.compile(sCol + SDext + ext);
		pRow = Pattern.compile(sRow + SDext + ext);
		pDiag1 = Pattern.compile(sDiag1 + SDext + ext);
		pDiag2 = Pattern.compile(sDiag2 + SDext + ext);

		for(String s : files)
		{
		    // See above for info
		    col = (col ? col : pCol.matcher(s).matches());
		    row = (row ? row : pRow.matcher(s).matches());
		    diag1 = (diag1 ? diag1 : pDiag1.matcher(s).matches());
		    diag2 = (diag2 ? diag2 : pDiag2.matcher(s).matches());
		}

		if(col && row && diag1 && diag2) //If the column and row and both diagonals found
		{
		    if(SoND) //If single, Style is XOS
		    {
			style.styleType = StyleTypes.XOS;
		    }
		    else
		    {
			col = row = diag1 = diag2 = false;

			SDext = "o";

			// Recompile patterns for checking for o images
			pCol = Pattern.compile(sCol + SDext + ext);
			pRow = Pattern.compile(sRow + SDext + ext);
			pDiag1 = Pattern.compile(sDiag1 + SDext + ext);
			pDiag2 = Pattern.compile(sDiag2 + SDext + ext);

			for(String s : files)
			{
			    // See above for info
			    col = (col ? col : pCol.matcher(s).matches());
			    row = (row ? row : pRow.matcher(s).matches());
			    diag1 = (diag1 ? diag1 : pDiag1.matcher(s).matches());
			    diag2 = (diag2 ? diag2 : pDiag2.matcher(s).matches());
			}

			if(col && row && diag1 && diag2)
			{
			    style.styleType = StyleTypes.XOD;
			}
		    }
		}
	    }
	}
	else //if(X&&O)
	{
	    style = null;
	}

	return style;
    }
}
